package demo.game.chess.common;

import java.util.ArrayList;
import java.util.List;

import demo.game.chess.common.CastlingException.EnumCastlingExceptionKind;

public class PieceKing extends AbstractChessPiece {

	public PieceKing(final ChessCell initialPosition) {
		super(initialPosition);
	}

	private ChessMove createCastlingMove(final ChessBoard board,
			final ChessCell origin, final ChessCell target)
			throws CastlingException {
		EnumCastling swapType = findSwapType(origin, target);

		if (swapType == null) {
			return null;
		}

		AbstractChessPiece rook = board
				.getPieceAt(swapType.getOriginRookCell());

		if (!(rook instanceof PieceRook) || rook.getColor() != getColor()) {
			return null;
		}

		// ensure no obstacle for swapping.
		List<ChessCell> path = swapType.getOriginKingCell().getPathTo(
				swapType.getOriginRookCell());
		for (ChessCell c : path) {
			if (null != board.getPieceAt(c)) {
				return null;
			}
		}

		ChessMove move = new ChessMove(origin, target, swapType);

		if (board.hasPieceMoved(swapType.getOriginKingCell())) {
			throw new CastlingException(move,
					EnumCastlingExceptionKind.king_already_moved);

		}

		if (board.hasPieceMoved(swapType.getOriginRookCell())) {
			throw new CastlingException(move,
					EnumCastlingExceptionKind.rook_already_moved);
		}

		if (board.isCheck()) {
			throw new CastlingException(move,
					EnumCastlingExceptionKind.king_in_check);
		}

		List<ChessCell> cellsToCheck = new ArrayList<ChessCell>(path);
		cellsToCheck.add(target);
		for (ChessCell c : cellsToCheck) {
			ChessMove attack = board.findKingAttackInSquare(getColor(), c);
			if (null != attack) {
				throw new CastlingException(move, board.getPieceAt(attack
						.getOriginCell()), attack);
			}
		}

		return move;
	}

	@Override
	protected ChessMove createPieceSpecificMove(final ChessBoard board,
			final ChessCell origin, final ChessCell target)
			throws CastlingException {
		int diffRow = target.getRow() - origin.getRow();
		int diffCol = target.getColumn() - origin.getColumn();

		if (Math.abs(diffRow) > 1) {
			return null;
		}

		if (Math.abs(diffCol) > 1) {

			return createCastlingMove(board, origin, target);

		} else {

			return new ChessMove(origin, target);
		}
	}

	private EnumCastling findSwapType(final ChessCell origin,
			final ChessCell target) {
		for (EnumCastling t : EnumCastling.values()) {
			if (t.getTargetKingCell().equals(target)
					&& t.getOriginKingCell().equals(origin)) {
				return t;
			}
		}
		return null;
	}

	@Override
	public EnumChessPiece getType() {
		return EnumChessPiece.king;
	}
}
